package system

import (
	"gin-admin/common/dto/request"
	"gin-admin/common/dto/response"
	"gin-admin/core"
	"gin-admin/enumeration"
	"gin-admin/global"
	"gin-admin/model"
	serviceRequest "gin-admin/service/dto/request"
	serviceResponse "gin-admin/service/dto/response"
	"gin-admin/utils"
	"time"
)

type UserService struct{}

var UserServiceApp = &UserService{}

func (us *UserService) CreateUserService(requestData *serviceRequest.CreateUserRequest) *response.ServiceError {
	db := global.GA_DB
	var user model.User
	condition := core.BuildQueryCondition("account", requestData.Account)
	exists, err := core.CheckDataExistsByCondition(db, condition, &user)
	if err != nil {
		return err
	}
	if exists {
		return response.WrapError(response.UserAccountExistsCode, response.GetStatusCode(response.UserAccountExistsCode).Message)
	}
	pwd, _ := utils.GeneratePassword(requestData.Password)
	user = model.User{
		Account:  requestData.Account,
		Password: pwd,
	}
	if err := core.GenericCreateWithModel(db, &user); err != nil {
		return err
	}
	return nil
}

func (uc *UserService) DeleteUserService(requestData *request.IDRequest) *response.ServiceError {
	var user model.User
	exists, err := core.CheckDataExistsByCondition(global.GA_DB, &requestData, &user)
	if err != nil {
		return err
	}
	if !exists {
		return response.WrapError(response.UserNotFoundCode, response.GetStatusCode(response.UserNotFoundCode).Message)
	}
	if err := core.GenericLogicalDelete(global.GA_DB, &user); err != nil {
		return err
	}
	return nil
}

func (uc *UserService) ModifyUserService(requestData *serviceRequest.ModifyUserRequest) *response.ServiceError {
	var user model.User
	condition := core.BuildQueryCondition("id", requestData.ID)
	exists, err := core.CheckDataExistsByCondition(global.GA_DB, condition, &user)
	if err != nil {
		return err
	}
	if !exists {
		return response.WrapError(response.UserNotFoundCode, response.GetStatusCode(response.UserNotFoundCode).Message)
	}
	if err := core.GenericUpdateWithModel(global.GA_DB, &user, &requestData); err != nil {
		return err
	}
	return nil
}

func (us *UserService) GetUserInfoService(id string) (*serviceResponse.UserResponse, *response.ServiceError) {
	var user model.User
	var userResponse serviceResponse.UserResponse
	if _, err := core.GenericQueryById(global.GA_DB, id, &user, func() *response.ServiceError {
		return response.WrapError(response.UserNotFoundCode, response.GetStatusCode(response.UserNotFoundCode).Message)
	}); err != nil {
		return nil, err
	}
	if err := utils.ModelToStruct(&userResponse, user); err != nil {
		return nil, err
	}
	userResponse.StatusName = enumeration.UserStatus(user.Status).StatusString()
	userResponse.GenderName = enumeration.UserGender(user.Gender).GenderString()
	return &userResponse, nil
}

func (us *UserService) GetUserListService(requestData *serviceRequest.UserListRequest) (*response.PaginationResponse, *response.ServiceError) {
	var users []model.User
	var userListResponse response.PaginationResponse
	var userInfoResponse serviceResponse.UserResponse
	result, err := core.GenericQueryByPagination(global.GA_DB, requestData, &users)
	if err != nil {
		return nil, err
	}

	for _, user := range users {
		if err := utils.ModelToStruct(&userInfoResponse, &user); err != nil {
			return nil, err
		}
		userInfoResponse.StatusName = enumeration.UserStatus(user.Status).StatusString()
		userListResponse.List = append(userListResponse.List, userInfoResponse)
	}
	userListResponse.Page = result.Page
	userListResponse.Size = result.Size
	userListResponse.Total = result.Total
	return &userListResponse, nil
}

func (us *UserService) LoginService(requestData *serviceRequest.LoginRequest) (*serviceResponse.LoginResponse, *response.ServiceError) {
	var user model.User
	condition := core.BuildQueryCondition(map[string]interface{}{
		"account": requestData.Account,
		"email":   requestData.Account,
		"mobile":  requestData.Account,
	})
	if err := core.GenericQueryTakeByCondition(global.GA_DB, condition, "OR", &user, func() *response.ServiceError {
		return response.WrapError(response.UserNotFoundCode, response.GetStatusCode(response.UserNotFoundCode).Message)
	}); err != nil {
		return nil, err
	}
	verify := utils.VerifyPasswordWithHashedPassword(user.Password, requestData.Password)
	if !verify {
		return nil, response.WrapError(response.UserAccountOrPasswordFailedCode, response.GetStatusCode(response.UserAccountOrPasswordFailedCode).Message)
	}
	_, token, _ := utils.GenerateToken(user.UserID, user.IsAdmin)
	redisUtils := &utils.RedisUtils{}
	redisUtils.Set(ctx, user.UserID, token, time.Duration(global.GA_CONFIG.Jwt.ExpiresAt)*time.Second)
	var loginResponse = serviceResponse.LoginResponse{
		Token: token,
	}
	return &loginResponse, nil
}
